from optparse import OptionParser, Option, Values
from ConfigParser import ConfigParser
from warnings import warn
import re

__all__ = ["EnvisatOptions", "EnvisatConfig", "EnvisatModel"]

cfgfile = Option("-c", "--config",
	help="config file [default /etc/envisat.cfg]",
	action="store",
	type="string",
	default="/etc/envisat.cfg"
)

class EnvisatOptions(OptionParser):
	standard_option_list = [cfgfile]

class EnvisatConfig(ConfigParser):
	## Override the regular expression in the parent class since we 
	## do not want : to be a key/value separator to permit using 
	## URLs as keys.
	OPTCRE = re.compile(
		r'(?P<option>[^=\s][^=]*)'	# very permissive!
		r'\s*(?P<vi>[=])\s*'		# any number of space/tab,
						# followed by separator
						# (=), followed
						# by any # space/tab
		r'(?P<value>.*)$'		# everything up to eol
	)

	def __init__(self, options):
		ConfigParser.__init__(self)
		cfgfile = options.config
		self.read([cfgfile])

	def has_predicate(self, node):
		"""
		Check if the given predicate is enabled in this configuration.
		This means that it must be present in the [predicates] section
		of the configuration file, or the "default" value in that section
		must be set to true.

		A predicate may be specified either as a complete URL, or else
		of the form prefix:rest where prefix is defined in the [namespaces]
		section of the config.

		The predicate must convert to a string URI when coerced to a string.
		This is true of strings themselves, obviously, as well as RDF.Uri
		objects.

		>>> from tempfile import mktemp
		>>> from os import unlink
		>>> options = Values({ 'config' : mktemp() })
		>>> fp = open(options.config, "w+")
		>>> fp.write(testconfig)
		>>> fp.close()
		>>> config = EnvisatConfig(options)
		>>> config.has_predicate("http://example.org/test#name")
		False
		>>> config.has_predicate("http://example.org/test#label")
		False
		>>> config.has_predicate("http://example.org/test#comment")
		True
		>>> config.has_predicate("http://example.org/test#nonexistent")
		True
		>>> unlink(options.config)
		"""
		uri = str(node)
		if self.has_option("predicates", uri):
			return self.getboolean("predicates", uri)
		for pfx, ns in self.items("namespaces"):
			if ns == uri[:len(ns)]:
				uri = pfx + ":" + uri[len(ns):]
				if self.has_option("predicates", uri):
					return self.getboolean("predicates", uri)
		if self.has_option("predicates", "default"):
			return self.getboolean("predicates", "default")
		return False

def EnvisatModel(config):
	"""
	Create an RDF.Model instance from storage parameters
	present in the configuration file. Arguments such as
	may be given to RDF.Storage should be present in the
	configuration in a section called [store].
	"""
	try:
		from RDF import Model, Storage
	except ImportError:
		warn("RDF not present", RuntimeWarning)
		return
	
	##
	## Defaults
	##
	storage_options = {
		"storage_name" : "memory",
		"name" : "memory",
		"options_string" : ""
	}

	if config.has_section("store"):
		for k in storage_options:
			if config.has_option("store", k):
				storage_options[k] = config.get("store", k)

	storage = Storage(**storage_options)
	model = Model(storage)
	return model

testconfig = """
[namespaces]
example=http://example.org/test#

[predicates]
default=true
example:name=false
http://example.org/test#label=false
example:comment=true
"""

if __name__ == '__main__':
	import doctest
	doctest.testmod()
